﻿#include <thread>
#include <eventloop.h>
#include <ReflectableObject.h>
#include <metaproperty.h>
#include <metasignal.h>

#include <Timer.h>
#include <threadpool.h>

#include "RXNode.h"
#include "RXEntity.h"
#include "RXWorld.h"
#include "RXAspect.h"
#include "RXAspectEngine.h"
#include "RXShadowWorld/RXShadowWorld.h"

#define DEFAULT_WORK_THREAD 4

struct AspectJobInfo
{
	RXECSDef::AspectJobList jobs;
	bool isFinished = false;
	bool isBegin = false;
	std::vector<RXAspect*> Relys;
};

class AspectJobController
{
public:
	AspectJobController() :m_threadPool(DEFAULT_WORK_THREAD, DEFAULT_WORK_THREAD, ThreadPool::Fixed) {

	}

	~AspectJobController() {
		m_threadPool.stop();
	}

	void Post(const std::map<RXAspect*, AspectJobInfo>& infos, std::function<void()> callBack) {
		this->infos = infos;
		this->callBack = callBack;

		RXECSDef::AspectJobList allTask;

		for (const auto &i : infos) {
			allTask.insert(allTask.end(), i.second.jobs.begin(), i.second.jobs.end());
		}

		auto job = RXECSDef::AspectJob::CreateJob(callBack, allTask);
		m_threadPool.PostJob(job);

		OnAspectJobFinished(NULL);
	}

	void OnAspectJobFinished(RXAspect* aspect) {
		std::unique_lock<std::mutex> lock(m_mutex);
		if (infos.count(aspect)) {
			auto& job = infos.at(aspect);
			job.isFinished = true;
		}

		for (auto &i : infos) {

			if (i.second.isFinished || i.second.isBegin) {
				continue;
			}


			bool flag = true;
			for (const auto &j : i.second.Relys)
			{
				if (!infos.at(j).isFinished) {
					flag = false;
					break;
				}
			}

			if (!flag) {
				continue;
			}

			auto jobs = i.second.jobs;
			auto aspect = i.first;
			i.second.isBegin = true;

			jobs.push_back(ThreadJob::CreateJob([=]() {
				OnAspectJobFinished(aspect);
			}, { jobs }));

			m_threadPool.PostJob(jobs);

		}
	}

private:
	std::map<RXAspect*, AspectJobInfo> infos;
	std::function<void()> callBack;
	ThreadPool m_threadPool;
	std::mutex m_mutex;
};

class RXAspectEngine::WorldListener:public RXWorldEventListenr
{
public:
	WorldListener(RXAspectEngine* engine) {
		this->engine = engine;
	}
	void NodeSpawned(RXNode* node,bool isRoot) override{
		engine->slotOnNewNodeSpawned_Front(node,isRoot);
	}
	void NodeDeleted(RXECSDef::NodeId id) override {
		engine->slotOnNodeDestoried_Front(id);
	}

	void NodeEventToShadow(RXECSDef::NodeId id, ThreadSafe::Event* e) override {
		engine->slotOnNodeEvent_Front(id, e);
	}

	void NodePropertyChanged(RXECSDef::NodeId id, int PropertyId, Variant value) override {
		engine->slotOnPropertyChanged_Front(id, PropertyId, value);
	}

	RXAspectEngine* engine;
};

struct AspectCacheData
{
	std::map<RXAspect*, std::vector<RXAspect*>> m_relys;//aspect依赖表
	std::vector<RXAspect*> m_relyList;//根据依赖表生成的依赖序列
};

struct RXAspectEngine::Private
{
	std::unique_ptr<RXWorld> m_World;

	std::unique_ptr<ReflectableObject> m_context;

	std::set<RXAspect*> m_aspectList;
	AspectCacheData m_aspectCacheData;//关于aspect的缓存数据

	std::unique_ptr<AspectJobController> m_jobcontroller;

	std::chrono::system_clock::duration min_interval;
	std::chrono::system_clock::time_point last_time;
	std::chrono::system_clock::duration world_delta;
};

RXAspectEngine::RXAspectEngine(const std::vector<RXAspect*>& aspects):_P(new Private)
{
	
	for (auto i : aspects) {
		if (_P->m_aspectList.count(i)) {
			return;
		}

		i->engine = this;
		_P->m_aspectList.insert(i);
	}

	_P->m_context.reset(new ReflectableObject());

	_P->m_World.reset(new RXWorld());

	_P->m_World->AddWorldListener(RXWorldEventListenrPtr(new WorldListener(this)));//添加世界监听器

	_P->m_jobcontroller.reset(new AspectJobController());

	SetMaxFPS(30);

	InitAspect();

	BeginFrame();
}

RXAspectEngine::~RXAspectEngine()
{
	_P->m_jobcontroller.reset();

	for (auto &i : _P->m_aspectList) {
		delete i;
	}
}

RXWorld * RXAspectEngine::GetWorld()
{
	return _P->m_World.get();
}

void RXAspectEngine::SetMaxFPS(int FPS)
{
	_P->min_interval = std::chrono::milliseconds(1000) / FPS;
}

int RXAspectEngine::GetMaxFPS() const
{
	return std::chrono::milliseconds(1000) / _P->min_interval;
}

void RXAspectEngine::CollectCreationInfo(RXNode* root, RXECSDef::NodeCreationInfoPtr ret,bool isRoot) {
	RXECSDef::NodeCreationInfo &info = *ret;
	info.meta = root->GetMetaInfo();
	auto p = dynamic_cast<RXNode*>(root->GetParent());
	if (p) {
		info.parentNodeId = p->GetNodeId();
	}
	else {
		info.parentNodeId = 0;
	}

	auto id = root->GetNodeId();
	info.id = id;
	info.isRoot = isRoot;

	void* root_void = dynamic_cast<void*>(root);
	for (int i = 0; i < info.meta.PropertyCount(); i++) {
		auto prop = info.meta.GetProperty(i);
		info.init_property[i] = prop.GetValue(root_void);
	}
}

void RXAspectEngine::PostToFrontNode(RXECSDef::NodeId nodeId, ThreadSafe::Event * event)
{
	EventLoop::PostEvent(_P->m_context.get(), new ThreadSafe::InvokeFunctionEvent([=]() {//控制权转移到前端

		auto node = _P->m_World->GetNode(nodeId);

		if (!node)//节点找不到 可能是被析构了
		{
			delete event;
		}

		EventLoop::PostEvent(node, event);//向节点发送事件
	}));
}

RXAspectService * RXAspectEngine::AcquireAspectService(const RXECSDef::RXAspectServiceID& name)
{
	for (auto i : _P->m_aspectList) {
		if (i->m_services.count(name)) {
			return i->m_services[name].get();
		}
	}

	return nullptr;
}

void RXAspectEngine::RegisterNodeType(MetaInfo meta)
{
	_P->m_World->RegisterClass(meta);
}

void BuildRelyData(const std::set<RXAspect*> &input,std::map<RXAspect*, std::vector<RXAspect*>> &m_relys, std::vector<RXAspect*> &m_relyList) {
	
	std::set<RXAspect*> rest = input;
	std::set<RXAspect*> completed;

	std::map<std::string, RXAspect*> mapAspName;
	std::map<RXAspect*, std::vector<RXAspect*>> mapref;
	for (const auto &i : rest) {
		const auto& info = i->GetAspectInfo();
		mapAspName[info.GetName()] = i;
	}

	for (const auto &i : rest) {
		const auto& info = i->GetAspectInfo();
		for (const auto & j : info.GetRelyAspects()) {
			auto r = mapAspName.at(j);
			if (!r) {
				std::cerr << "无法加载Aspect:" << info.GetName() << "缺少依赖Aspect:" << j << std::endl;
				assert(false);
			}
			m_relys[i].push_back(r);
		}
	}

	while (!rest.empty())
	{
		RXAspect* aspect = 0;
		for (auto &i : rest) {
			bool flag = true;

			const auto& info = i->GetAspectInfo();

			for (const auto &j : m_relys[i]) {
				if (!completed.count(j)) {
					flag = false;
					break;
				}
			}

			if (flag) {
				aspect = i;
				break;
			}
		}

		if (!aspect) {
			std::cerr << "引擎启动失败,Aspect依赖可能存在环路" << std::endl;
			assert(false);
		}

		m_relyList.push_back(aspect);
		rest.erase(aspect);
		completed.insert(aspect);
	}
}

void RXAspectEngine::BuildCacheData()
{
	BuildRelyData(_P->m_aspectList,_P->m_aspectCacheData.m_relys,_P->m_aspectCacheData.m_relyList);
	
}

void RXAspectEngine::slotOnNewNodeSpawned_Front(RXNode * node,bool isRoot)
{
	RXECSDef::NodeCreationInfoPtr ret(new RXECSDef::NodeCreationInfo());//收集节点创建信息，转投给后端线程
	CollectCreationInfo(node, ret, isRoot);
	
	EventLoop::PostEvent(_P->m_context.get(), new ThreadSafe::InvokeFunctionEvent([=]() {
		slotOnNewNodeSpawned_Shadow(ret);
	}));
}

void RXAspectEngine::slotOnNewNodeSpawned_Shadow(RXECSDef::NodeCreationInfoPtr info)
{
	//此函数在Shadow线程执行
	for (auto i : _P->m_aspectList) {
		i->HandleNodeSpawnEvent(info);
	}
}

void RXAspectEngine::slotOnPropertyChanged_Front(RXECSDef::NodeId node, int propertyIndex, Variant value)
{
	//收集节点属性修改信息，转投给后端线程
	RXECSDef::NodePropertyChangeEventPtr ret(new RXECSDef::NodePropertyChangeEvent());

	ret->id = node;
	ret->propIndex = propertyIndex;

	//节点指针无法直接通行，转换为节点id
	MetaType type(value.TypeId());
	if (type.isPointerToReflectable())
	{
		value.Convert(MetaType::IdFromType<RXNode*>());
	}

	ret->value = value;

	EventLoop::PostEvent(_P->m_context.get(), new ThreadSafe::InvokeFunctionEvent([=]() {
		slotOnPropertyChanged_Shadow(ret);
	}));
}

void RXAspectEngine::slotOnPropertyChanged_Shadow(RXECSDef::NodePropertyChangeEventPtr info)
{
	for (auto i : _P->m_aspectList) {
		i->HandleNodePropertyChangeEvent(info);
	}
}

void RXAspectEngine::slotOnNodeDestoried_Front(RXECSDef::NodeId node)
{
	EventLoop::PostEvent(_P->m_context.get(), new ThreadSafe::InvokeFunctionEvent([=]() {
		slotOnNodeDestoried_Shadow(node);
	}));
}

void RXAspectEngine::slotOnNodeDestoried_Shadow(RXECSDef::NodeId id)
{
	for (auto i : _P->m_aspectList) {
		i->HandleNodeDestoryEvent(id);
	}
}

void RXAspectEngine::slotOnNodeEvent_Front(RXECSDef::NodeId node, ThreadSafe::Event * event)
{
	EventLoop::PostEvent(_P->m_context.get(), new ThreadSafe::InvokeFunctionEvent([=]() {
		slotOnNodeEvent_Shadow(node, event);
	}));
}

void RXAspectEngine::slotOnNodeEvent_Shadow(RXECSDef::NodeId id, ThreadSafe::Event * event)
{
	for (auto i : _P->m_aspectList) {
		i->HandleNodePostEvent(id,event);
	}

	delete event;
}

void RXAspectEngine::BeginFrame()
{
	_P->last_time = std::chrono::system_clock::now();
	PostFrame();
}

void RXAspectEngine::PostFrame()
{
	auto now = std::chrono::system_clock::now();
	auto delta = now - _P->last_time;
	if (delta < _P->min_interval) {
		Timer::SingleShot(_P->last_time + _P->min_interval, [=]() {
			HandleFrame();
		}, _P->m_context.get());
	}
	else {
		EventLoop::PostEvent(_P->m_context.get(), new ThreadSafe::InvokeFunctionEvent([=]() {
			HandleFrame();
		}));
	}
}

void RXAspectEngine::HandleFrame()
{
	auto now = std::chrono::system_clock::now();
	auto delta = now - _P->last_time;
	_P->world_delta = delta;
	_P->last_time = now;
	std::map<RXAspect*, AspectJobInfo> jobinfo;

	for (auto i : _P->m_aspectCacheData.m_relyList) {
		auto && job = i->CreateAspectJob(delta);
		AspectJobInfo info;
		info.jobs = job;
		info.Relys = _P->m_aspectCacheData.m_relys[i];
		jobinfo[i] = info;
	}

WorkCondition cond(1);

//帧任务虽然是在其它线程处理的，但为了安全，它是同步的，当处理帧事件时不会去处理节点属性等事件以免造成多线程混乱
//启动线程池处理切面任务
_P->m_jobcontroller->Post(jobinfo, [&]() {
	cond.FinishWork();
});
//等待任务处理完毕
cond.WaitForFinished();
OnFrameFinished();
}

void RXAspectEngine::OnFrameFinished()
{
	PostFrame();
}

void RXAspectEngine::InitAspect()
{
	auto rest = _P->m_aspectList;

	BuildCacheData();

	for (auto i : _P->m_aspectCacheData.m_relyList) {
		i->AspectBegin();
	}
}
